#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#include <pthread.h>

#define MSIZE 2048
#define WRITE 1
#define QUIT 2


typedef enum
{
     INFO = 1,
     WARNING,
     ERROR,
     CRITICAL
} log_priority_t;

typedef enum
{
     DEBUG = 1,
     TEST,
     FINAL
} log_version_t;

typedef struct
{
     long mtype;
     log_priority_t mpriority;
     char mtext[MSIZE];
} log_message_t;

typedef struct
{
     log_version_t program_type;
     const char* file_name;
     int log_id;
} log_args_t;

typedef pthread_t logger_t;

void* logger_thread (void *args)
{
     log_args_t *arg = (log_args_t *) args;
     log_version_t program_type = arg->program_type;
     int log_id = arg->log_id;
     const char* file_name = arg->file_name;
   
     FILE* output = fopen (file_name, "w"); 
     
     log_message_t msg;

     
     do{
	  msgrcv(log_id, &msg, sizeof(log_message_t) - sizeof(long), 0, 0);
	  if(msg.mpriority >= program_type) fprintf(output, msg.mtext);
     }
     while (msg.mtype != QUIT);
     
     fclose (output);
     pthread_exit(0);
}

int log_init (log_version_t program_type, const char* file_name, logger_t *logger)
{
     int log_id;
     log_id = msgget (1, 0666 | IPC_CREAT);
     
     if (log_id < 0){
	  printf ("LogInitError: Failed to create message queue.\n");
	  return -1;
     }
     //else printf ("LogInit: Message queue was successfully created.\n");
     
     log_args_t args;
     
     args.program_type = program_type;
     args.log_id = log_id;
     args.file_name = file_name;
     
     if (pthread_create (logger, NULL, logger_thread, &args) < 0){ 
	  printf ("LogInitError: Failed to create logger's thread.\n");
	  if (msgctl (log_id, IPC_RMID, NULL) < 0) printf ("LogInitError: Failed to remove message queue.\n");
	  else printf ("LogInit: Message queue was successfully removed.\n");
	  return -1;
     }
     //else printf ("LogInit: Logger's thread was successfully created.\n");


     return log_id;
}



int log_write (int log_id, log_priority_t message_priority, const char *text){
     
     log_message_t msg;
     
     strcpy(msg.mtext, text);
     msg.mtype = WRITE;
     msg.mpriority = message_priority;
     
     msgsnd(log_id, &msg, sizeof(log_message_t) - sizeof(long), 0);

     return 0;
}


int log_deinit(int log_id, logger_t logger)
{
     log_message_t msg;
     msg.mtype = QUIT;
     msg.mpriority = 0;
     
     msgsnd(log_id, &msg, sizeof(log_message_t) - sizeof(long), 0);
     
     if (pthread_join(logger, NULL) != 0){
	  printf ("LogDeinitError: Logger's thread ended with error.\n");
	  return -1;
     }
     //else printf("LogDeinit: Logger's thread ended correct.\n");
     
     if (msgctl(log_id, IPC_RMID, NULL) < 0){
	  printf("LogDeinitError: Failed to remove message queue.\n");
	  return -1;
     }
     //else printf ("LogDeinit: Message queue was successfully removed.\n");

     return 0;
}
